package cn.gailvlun.gll.chatkit.message;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.graphics.drawable.AnimationDrawable;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.support.v7.widget.LinearLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.github.markzhai.recyclerview.BaseViewAdapter;
import com.github.markzhai.recyclerview.BindingViewHolder;
import com.github.markzhai.recyclerview.MultiTypeAdapter;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import cn.gailvlun.gll.chatkit.BR;
import cn.gailvlun.gll.chatkit.PlayerService;
import cn.gailvlun.gll.chatkit.R;
import cn.gailvlun.gll.chatkit.databinding.ItemMessageOutcomingBinding;
import cn.gailvlun.gll.chatlib.ChatClient2;
import cn.gailvlun.gll.chatlib.db.ChatDB2;
import cn.gailvlun.gll.chatlib.message.Message;
import cn.gailvlun.gll.chatlib.message.MessageStatus;
import cn.gailvlun.gll.chatlib.message.MessageType;
import cn.gailvlun.gll.net.base.Profile;
import cn.gailvlun.gll.util.DateUtil;
import cn.gailvlun.gll.util.LogUtil;
import cn.gailvlun.gll.util.RxUtil;
import cn.gailvlun.gll.util.ToastUtil;
import io.reactivex.functions.Consumer;
import io.realm.Realm;



public class MessageListAdapter extends MultiTypeAdapter {

    private List<MessageType> messageType = new ArrayList<>();

    private void addViewTypeByMessageMgr() {
        int viewType = 0;
        addViewTypeToLayoutMap(viewType++, R.layout.item_message_time);
        addViewTypeToLayoutMap(viewType++, R.layout.item_message_init_info);

        for (int i = 0; i < MessageMgr.getInstance().getClassList().size(); i++) {
            addViewTypeToLayoutMap(viewType++, R.layout.item_message_outcoming);
            addViewTypeToLayoutMap(viewType++, R.layout.item_message_incoming);
        }
    }

    private Context mContext;

    private PlayerService.PlayerBinder mBinder;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinder = (PlayerService.PlayerBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBinder = null;
        }
    };

    public MessageListAdapter(final Context context) {
        super(context);
        mContext = context;

        addViewTypeByMessageMgr();

        Intent intent = new Intent(mContext, PlayerService.class);
        mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);

        setPresenter(new Presenter());
        setDecorator(new Decorator() {
            @Override
            public void decorator(final BindingViewHolder holder, final int position, int viewType) {
                final int truePosition = holder.getAdapterPosition();
                
                ViewDataBinding comingBinding = holder.getBinding();

                if (messageType.get(position) == MessageType.time) {
                    comingBinding.setVariable(BR.message, mCollection.get(position));
                } else if (messageType.get(position) == MessageType.initInfo) {
                    comingBinding.setVariable(BR.message, mCollection.get(position));
                } else {
                    if (comingBinding instanceof ItemMessageOutcomingBinding) {
                        if (onResendClickListener != null) {
                            ((ItemMessageOutcomingBinding) comingBinding).ivResend.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    int adapterPosition = holder.getAdapterPosition();
                                    Message msg = (Message) mCollection.get(adapterPosition);
                                    onResendClickListener.onResend(msg, holder);
                                }
                            });
                        }
                    }

                    ViewGroup vg = comingBinding.getRoot().findViewById(R.id.ll);
                    ViewDataBinding messageBinding = null;
                    if (vg.getChildCount() == 0) {
                        messageBinding = DataBindingUtil.inflate(LayoutInflater.from(context),
                                MessageMgr.getInstance().getLayoutList().get(MessageMgr.getInstance().getClassList().indexOf(messageType.get(position))),
                                vg, true);
                        messageBinding.setVariable(BR.message, mCollection.get(holder.getAdapterPosition()));
                    } else {
                        messageBinding = DataBindingUtil.findBinding(vg.getChildAt(0));
                        messageBinding.setVariable(BR.message, mCollection.get(holder.getAdapterPosition()));
                    }

                    if (messageType.get(position) == MessageType.walkieTalkie) {
                        Message vm = (Message) mCollection.get(position);
                        messageBinding.setVariable(BR.isLeft, !vm.isMe());
                        if (mBinder != null) {
                            if (mBinder.isPlaying() &&
                                    mBinder.getCurrentPlaying() == mCollection.get(holder.getAdapterPosition())) {
                                ImageView ivLeft = messageBinding.getRoot().findViewById(R.id.iv_voice_left);
                                ImageView ivRight = messageBinding.getRoot().findViewById(R.id.iv_voice_right);

                                final ImageView visibleVoice = !vm.isMe() ? ivLeft : ivRight;
                                final AnimationDrawable ad = (AnimationDrawable) visibleVoice.getBackground();
                                visibleVoice.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        ad.start();
                                        mBinder.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                                            @Override
                                            public void onCompletion(MediaPlayer mp) {
                                                ad.stop();
                                                ad.selectDrawable(0);
                                            }
                                        });
                                    }
                                });
                            }
                        }
                    }

                    if (mOnMessageClickListener != null) {
                        final ViewDataBinding finalMessageBinding = messageBinding;
                        messageBinding.getRoot().setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                View view = finalMessageBinding.getRoot();
                                int adapterPosition = holder.getAdapterPosition();
                                Message message = (Message) mCollection.get(adapterPosition);
                                if (message.getType() == MessageType.walkieTalkie) {
                                    if (mBinder != null) {
                                        ImageView ivLeft = view.findViewById(R.id.iv_voice_left);
                                        ImageView ivRight = view.findViewById(R.id.iv_voice_right);

                                        final ImageView visibleVoice = !message.isMe() ? ivLeft : ivRight;

                                        if (mBinder.isPlaying() && mBinder.getCurrentPlaying() == message) {
                                            mBinder.stopAudio();
                                        } else {
                                            mBinder.stopAudio();
                                            mBinder.playAudio(message);
                                            final AnimationDrawable ad = (AnimationDrawable) visibleVoice.getBackground();
                                            ad.start();
                                            mBinder.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                                                @Override
                                                public void onCompletion(MediaPlayer mp) {
                                                    ad.stop();
                                                    ad.selectDrawable(0);
                                                }
                                            });
                                            
                                            if (!message.getWTPlayed()) {
                                                Realm realm = Realm.getInstance(ChatDB2.INSTANCE.getConfiguration());
                                                realm.beginTransaction();
                                                message.setWTPlayed(true);
                                                realm.commitTransaction();
                                                realm.close();

                                                notifyItemChanged(position);
                                            }
                                        }
                                    }
                                }

                                mOnMessageClickListener.onMessageClick(finalMessageBinding.getRoot(), message, adapterPosition);
                            }
                        });
                    }

                    if (mOnMessageLongClickListener != null) {
                        messageBinding.getRoot().setOnLongClickListener(new View.OnLongClickListener() {
                            @Override
                            public boolean onLongClick(View v) {
                                return mOnMessageLongClickListener.onMessageLongClick((Message) mCollection.get(position));
                            }
                        });
                    }
                }
            }
        });
    }

    public void addLatest(Message viewModel, boolean scrollToBottom) {
        
        

        if (mCollection.size() == 0 ||
                !DateUtil.isInFiveMinute(((Message) mCollection.get(0)).getCreated(),
                        viewModel.getCreated())) {
            
            Message timeMsg = new Message();
            timeMsg.setType(MessageType.time);
            timeMsg.setCreated(viewModel.getCreated());

            int viewType = getTypeByObject(timeMsg);
            this.messageType.add(0, timeMsg.getType());
            super.add(0, viewModel, viewType);
        }

        
        int viewType = getTypeByObject(viewModel);
        this.messageType.add(0, viewModel.getType());
        super.add(0, viewModel, viewType);

        if (scrollToBottom) {
            
            scrollToBottom();
        }
    }

    public Message getOldestMessage() {
        return (Message) mCollection.get(mCollection.size() - 1);
    }

    public void addDescendingMessages(List<Message> messages) {
        
        int formerCount = mCollection.size();

        for (int i = messages.size() - 1; i >= 0; i--) {
            if (i == messages.size() - 1 ||
                    !DateUtil.isInFiveMinute(messages.get(i).getCreated(), messages.get(i + 1).getCreated())) {
                Message timeMsg = new Message();
                timeMsg.setType(MessageType.time);
                timeMsg.setCreated(messages.get(i).getCreated());

                int viewType = getTypeByObject(timeMsg);
                this.messageType.add(formerCount, timeMsg.getType());
                mCollection.add(formerCount, timeMsg);
                mCollectionViewType.add(formerCount, viewType);
            }

            Message msg = messages.get(i);
            int viewType = getTypeByObject(msg);
            this.messageType.add(formerCount, msg.getType());
            mCollection.add(formerCount, msg);
            mCollectionViewType.add(formerCount, viewType);
        }

        notifyItemRangeInserted(formerCount, mCollection.size() - formerCount);
    }

    public void scrollToBottom() {
        
        if (mLayoutManager != null) {
            mLayoutManager.scrollToPositionWithOffset(0, 0);
        }
    }

    private int getTypeByObject(Message viewModel) {
        int viewType = 0;
        if (viewModel.getType() == MessageType.time) {
            viewType = 0;
        } else if (viewModel.getType() == MessageType.initInfo) {
            viewType = 1;
        } else {
            for (int i = 0; i < MessageMgr.getInstance().getClassList().size(); i++) {
                if (viewModel.getType()== MessageMgr.getInstance().getClassList().get(i)) {
                    if (viewModel.isMe()) {
                        viewType = 2 + i * 2;
                    } else if (!viewModel.isMe()) {
                        viewType = 3 + i * 2;
                    }
                }
            }
        }
        return viewType;
    }

    private LinearLayoutManager mLayoutManager;

    public void setLayoutManager(LinearLayoutManager layoutManager) {
        mLayoutManager = layoutManager;
    }

    public int getMessagePosition(Message msg) {
        return mCollection.indexOf(msg);
    }

    public void changeMessageToSuccess(String msgId) {
        for (int i = 0; i < mCollection.size(); i++) {
            Object o = mCollection.get(i);
            if (o instanceof Message && ((Message) o).getId().equals(msgId)) {
                ((Message) o).setMessageStatus(MessageStatus.SUCCESS);
                notifyItemChanged(i);
                break;
            }
        }
    }



    public interface OnMessageClickListener {
        void onMessageClick(View view, Message message, int position);
    }

    private OnMessageClickListener mOnMessageClickListener;

    public void setOnMessageClickListener(OnMessageClickListener onMessageClickListener) {
        this.mOnMessageClickListener = onMessageClickListener;
    }

    public interface OnMessageLongClickListener {
        boolean onMessageLongClick(Message message);
    }

    private OnMessageLongClickListener mOnMessageLongClickListener;

    public void setOnMessageLongClickListener(OnMessageLongClickListener onMessageLongClickListener) {
        this.mOnMessageLongClickListener = onMessageLongClickListener;
    }

    public interface OnClickPhotoListener {
        void onClickPhoto(Profile profile);
    }

    private OnClickPhotoListener mOnClickPhotoListener;

    public void setOnClickPhotoListener(OnClickPhotoListener onClickPhotoListener) {
        this.mOnClickPhotoListener = onClickPhotoListener;
    }

    public interface OnResendClickListener {
        void onResend(Message message, BindingViewHolder holder);
    }

    private OnResendClickListener onResendClickListener;

    public void setOnResendClickListener(OnResendClickListener onResendClickListener) {
        this.onResendClickListener = onResendClickListener;
    }

    public static class Util {
        public static float getVoiceMessageLength(Message message) {
            return 52 + message.getWtSecond() / 60f * 112f;
        }

        public static int getSpinnerVisibility(Message message) {
            if (message.getMessageStatus() == MessageStatus.FAIL_SPINNER) {
                return View.VISIBLE;
            }
            return View.GONE;
        }

        
        public static int getErrorVisibility(Message message) {
            switch (message.getMessageStatus()) {
                case FAIL_RESEND:
                case FAIL_UPLOAD: {
                    return View.VISIBLE;
                }
                default:
                    return View.GONE;
            }
        }

        public static int getUploadingVisibility(Message msg) {
            if (msg.getMessageStatus() == MessageStatus.UPLOADING) {
                return View.VISIBLE;
            }
            return View.GONE;
        }

        public static String getImageUrl(Message msg) {
            return msg.getRealImage();
        }

        public static String getRealVoiceSecond(Message voiceMsg) {
            return String.valueOf(voiceMsg.getWtSecond());
        }

        public static int getRoomNickAndTitleVisibility(Message message) {
            if (message.isRoom()) {
                return View.VISIBLE;
            } else {
                return View.GONE;
            }
        }

        public static String getRoomNick(Message message) {
            if (message.getNickName() != null) {
                return message.getNickName();
            }
            return message.getSender().getName();
        }

        public static String getRoomTitle(Message msg) {
            return "房主";
        }

        
        public static int getRoomTitleVisibility(Message msg) {
            if (msg.isRoom()) {
                if (msg.getSender().getId() == msg.getRoom().getOwner().getId()) {
                    return View.VISIBLE;
                }
            }
            return View.GONE;
        }
    }

    public class Presenter implements BaseViewAdapter.Presenter {
        public void onResend(final Message msg) {
            if (msg.getMessageStatus() == MessageStatus.FAIL_RESEND) {
                
                if (!ChatClient2.getInstance().sendMessage(msg)) {
                    msg.setMessageStatus(MessageStatus.FAIL_SPINNER);
                    
                    RxUtil.timer(10, TimeUnit.SECONDS)
                            .subscribe(new Consumer<Long>() {
                                @Override
                                public void accept(Long aLong) throws Exception {
                                    msg.setMessageStatus(MessageStatus.FAIL_RESEND);

                                }
                            });
                }
            }
        }

        public void onClickPhoto(Message msg) {
            LogUtil.d("onClickPhoto" + msg.getSender().getName());
            if (mOnClickPhotoListener != null) {
                mOnClickPhotoListener.onClickPhoto(msg.getSender());
            }
        }
    }

    public void unbindService() {
        mContext.unbindService(mServiceConnection);
    }
}
